#include <linux/module.h>
#include <linux/init.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/interrupt.h>

/*
	mykeys{
		interrupt-parent = <&gpiof>;
		interrupts = <9 0>,<7 0>, <8 0>; 
		interrupts-name = "key1", "key2", "key3";
	};
 */

MODULE_LICENSE("GPL");

typedef struct
{
    unsigned int m_irqNumber;
    const char* m_irqName;
}btn_desc;

static btn_desc btns[3];
static struct device_node* keysNode;
static struct tasklet_struct btnTasklet;
static int mycnt = 0x100;

irqreturn_t btn_irqHandler(int irqNumber, void* dev)
{
    btn_desc* data = (btn_desc*)dev;
	printk("enter top half, do urgency things...\n");//顶半部，处理紧急的事情，urgency[紧急]
    printk("%d: %s is pressed!\n",data->m_irqNumber, data->m_irqName);
	printk("register bottom half\n");
	tasklet_schedule(&btnTasklet);
	printk("exit from top half\n");
    return IRQ_HANDLED;
}

void btn_bottom_half_func(unsigned long data)
{
	int* mydata = (int*)data;
	printk("enter bottom half, do no urgency things...\n");
	printk("mycnt = %#x\n",(*mydata)++);
	// msleep(1);
}

static int __init btn_drv_init(void)
{
	int i=0, ret;
	keysNode = of_find_node_by_path("/mykeys");

	for(i=0;i<ARRAY_SIZE(btns);i++)
	{
		btns[i].m_irqNumber = irq_of_parse_and_map(keysNode,i);
		of_property_read_string_index(keysNode,"interrupts-name",i,&btns[i].m_irqName);

		ret = request_irq(btns[i].m_irqNumber, btn_irqHandler, IRQF_TRIGGER_FALLING,
			btns[i].m_irqName, &btns[i]);

		if(ret < 0)
			return ret;
	}
	
	tasklet_init(&btnTasklet, btn_bottom_half_func, (unsigned long)&mycnt);
	return 0;
}

static void __exit btn_drv_exit(void)
{
	int i =0;
	for(i=0;i<ARRAY_SIZE(btns);i++)
	{
		free_irq(btns[i].m_irqNumber,&btns[i]);
	}
}

module_init(btn_drv_init);
module_exit(btn_drv_exit);